package datastructure.utils;

import basics.iconcurrent.IThreadFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.Arrays;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author or2
 * @date 2021/7/19 22:23
 */
public class SolutionHelper {

    /**
     * 初始化线程池
     */
    private static final ReentrantLock REENTRANT_LOCK = new ReentrantLock();
    private static final IThreadFactory I_THREAD_FACTORY = new IThreadFactory(SortHelper.class);
    private static final ThreadPoolExecutor executorService = new ThreadPoolExecutor(2, 3,
            12L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(), I_THREAD_FACTORY);

    public static final String DEFAULT_METHOD = "resolve";

    static {
        executorService.allowCoreThreadTimeOut(true);
    }

    /**
     * 测试 数组 算法的解决方案
     * @param arr 提供测试数据的数组
     * @param clazz 测试方案的类元信息
     * @param methodName 所测算法所用方法名称
     * @param <E> {@code <E extends Comparable<E>>}
     */
    public static <E extends Comparable<E>> void testArraySolution(Class<?> clazz, String methodName, E[] arr) {
        Runnable task = () -> {
            if (arr.length < 10000) {
                synchronized (REENTRANT_LOCK) {
                    System.out.println("所测数组为:");
                    Arrays.stream(arr).forEach(Common::print);
                    System.out.println();
                }
            }

            Duration duration = Duration.ZERO;
            try {
                Method resolution = clazz.getMethod(methodName, Comparable[].class);
                long startTime = System.currentTimeMillis();
                resolution.invoke(null, (Object) arr);
                long endTime = System.currentTimeMillis();
                duration = Duration.ofMillis(endTime - startTime);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }

            synchronized (REENTRANT_LOCK){
                IPrint.printWithColor("问题: %s\n" +
                                "方案: %s\n" +
                                "花费事件: %s",
                        clazz.getName(), methodName, duration.toString().replace("PT", ""));
            }
        };
        executorService.submit(task);
    }

    public static <E extends Comparable<E>> void testArraySolution(Class<?> clazz, E[] arr) {
        testArraySolution(clazz, DEFAULT_METHOD, arr);
    }
}
